/**
 * 开源版本请务必保留此注释头信息，若删除捷码开源〔GEMOS〕官方保留所有法律责任追究！
 * 本软件受国家版权局知识产权以及国家计算机软件著作权保护（登记号：2018SR503328）
 * 不得恶意分享产品源代码、二次转售等，违者必究。
 * Copyright (c) 2020 gemframework all rights reserved.
 * http://www.gemframework.com
 * 版权所有，侵权必究！
 */
package com.gemframework.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gemframework.common.config.datasource.DBContextHolder;
import com.gemframework.common.config.datasource.DynamicDataSource;
import com.gemframework.common.exception.GemException;
import com.gemframework.common.utils.GemHTMLUtils;
import com.gemframework.mapper.DatasourceMapper;
import com.gemframework.model.common.BaseResultData;
import com.gemframework.model.entity.po.Datasource;
import com.gemframework.model.enums.DBConnStatus;
import com.gemframework.model.enums.ExceptionCode;
import com.gemframework.service.DatasourceService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Title: DBChangeServiceImpl
 * @Package: com.gemframework.common.config.druid
 * @Date: 2020-06-29 21:08:37
 * @Version: v1.0
 * @Description: 切换数据源服务实现
 * @Author: nine QQ 769990999
 * @Copyright: Copyright (c) 2020 wanyong
 * @Company: www.gemframework.com
 */
@Slf4j
@Service
public class DatasourceServiceImpl extends ServiceImpl<DatasourceMapper, Datasource> implements DatasourceService {

    @Autowired
    DatasourceMapper dataSourceMapper;

    @Resource
    DynamicDataSource dynamicDataSource;

    /**
     * 切换数据源
     * @param dsName
     * @return
     */
    @Override
    public boolean change(String dsName) {
        //默认切换到主数据源,进行整体资源的查找
        DBContextHolder.clearDataSource();
        List<Datasource> dataSourcesList = this.list();
        for (Datasource dataSource : dataSourcesList) {
            if (dataSource.getName().equals(dsName)) {
                log.info("需要使用的的数据源已经找到,dsName是：" + dataSource.getName());
                //创建数据源连接&检查若存在则不需重新创建
                boolean conn = dynamicDataSource.createDataSourceWithCheck(dataSource);
                if(conn){
                    //切换到该数据源
                    DBContextHolder.setDataSource(dataSource.getName());
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 测试连接
     * @param datasource
     * @return
     */
    @Override
    public boolean testConnection(Datasource datasource) {
        boolean conn = dynamicDataSource.testDatasource(datasource.getDriverClassName(),datasource.getUrl(),datasource.getUsername(),datasource.getPassword());
        datasource.setConnStatus(conn?DBConnStatus.SUCCESS.getCode():DBConnStatus.FAIL.getCode());
        this.updateById(datasource);
        return conn;
    }

    /**
     * 添加数据源
     * @param datasource
     * @return
     */
    @Override
    public boolean save(Datasource datasource) {
        if(exits(datasource)){
            throw new GemException(ExceptionCode.DATASOURCE_EXIST);
        }
        if(!super.save(datasource)){
            throw new GemException(ExceptionCode.SAVE_OR_UPDATE_FAIL);
        }
        return true;
    }

    /**
     * 删除数据源
     * @param id
     * @param ids
     * @return
     */
    @Override
    @Transactional
    public boolean delete(Long id, String ids) {
        if(id!=null) {
            this.removeById(id);

            //删除动态数据源 立即生效
            Datasource datasource = getById(id);
            dynamicDataSource.delDatasources(datasource.getName());
        }
        if(StringUtils.isNotBlank(ids)){
            List<Long> listIds = Arrays.asList(ids.split(",")).stream().map(s ->Long.parseLong(s.trim())).collect(Collectors.toList());
            if(listIds!=null && !listIds.isEmpty()){
                this.removeByIds(listIds);
            }

            //批量删除动态数据源
            List<Datasource> datasources = listByIds(listIds);
            if(datasources!=null && !datasources.isEmpty()){
                for(Datasource datasource:datasources){
                    dynamicDataSource.delDatasources(datasource.getName());
                }
            }
        }

        return true;
    }

    /**
     * 更新数据源信息
     * @param entity
     * @return
     */
    @Override
    @Transactional
    public boolean update(Datasource entity) {
        if(exits(entity)){
            throw new GemException(ExceptionCode.DATASOURCE_EXIST);
        }
        if(!super.updateById(entity)){
            throw new GemException(ExceptionCode.SAVE_OR_UPDATE_FAIL);
        }
        //删除已经创建的数据源-使用时重新获取连接
        dynamicDataSource.delDatasources(entity.getName());
        return true;
    }


    /**
     * 数据源是否存在
     * @param entity
     * @return
     */
    @Override
    public boolean exits(Datasource entity) {
        QueryWrapper<Datasource> queryWrapper = new QueryWrapper();
        queryWrapper.and(wrapper -> wrapper.eq("name",entity.getName()));
        if(entity.getId() != null && entity.getId() !=0){
            queryWrapper.ne("id",entity.getId());
        }
        if(count(queryWrapper)>0){
            return true;
        }
        return false;
    }
}